package javango.contrib.i18n;

import java.lang.reflect.InvocationTargetException;
import java.util.IllegalFormatException;
import java.util.Locale;
import java.util.Map;
import java.util.MissingFormatArgumentException;

import org.apache.commons.beanutils.NestedNullException;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;

public class AbstractI18NProvider implements I18NProvider { // yes not actually abstract,  probably needs to be renamed.

	protected Locale getLocale() {
		return new Locale("EN");
	}
	
	/**
	 * Translate the string into the correct language. Default implementation does nothing.  
	 * 
	 * @param string
	 * @return
	 */
	public String translate(Locale locale, String string) {
		return string;
	}
	
	public String getText(String formatString, Map<String, Object> args) throws IllegalFormatException {
		String format = translate(getLocale(), formatString);
		StringBuilder newFormat = new StringBuilder();
		
		int start = 0;
		int loc = format.indexOf("%(");
		Object[] newArgs = new Object[StringUtils.countMatches(format, "%(")];
		int argCount = 0;
		while (loc != -1) {
			loc++;
			newFormat.append(format.substring(start, loc));
			int end = format.indexOf(")", loc);
			String argName = format.substring(loc+1, end);
			if (!args.containsKey(argName)) {
				throw new MissingFormatArgumentException(argName);
			}
			Object value = args.get(argName);
			newArgs[argCount++] = value;
			start = end+1;
			loc = format.indexOf("%(", start);
		}
		newFormat.append(format.substring(start));
		return String.format(newFormat.toString(), newArgs);
	}
		
	public String getText(String formatString, Object argBean) throws IllegalFormatException {
		String format = translate(getLocale(), formatString);
		StringBuilder newFormat = new StringBuilder();
		
		int start = 0;
		int loc = format.indexOf("%(");
		Object[] newArgs = new Object[StringUtils.countMatches(format, "%(")];
		int argCount = 0;
		while (loc != -1) {
			loc++;
			newFormat.append(format.substring(start, loc));
			int end = format.indexOf(")", loc);
			String argName = format.substring(loc+1, end);
			
			try {
				if ( !PropertyUtils.isReadable(argBean, argName)) {
					throw new MissingFormatArgumentException(argName);
				}
				try {
					Object value = PropertyUtils.getProperty(argBean, argName);
					newArgs[argCount++] = value;
				} catch (InvocationTargetException e) {
					throw new MissingFormatArgumentException("Exception while getting: (InvocationTargetException)" + argName);
				} catch (IllegalAccessException e) {
					throw new MissingFormatArgumentException("Exception while getting: (IllegalAccessException)" + argName);
				} catch (NoSuchMethodException e) {
					throw new MissingFormatArgumentException("Exception while getting: (NoSuchMethodException)" + argName);
				}
			} catch (NestedNullException e) {
				newArgs[argCount++] = "";
			}
			start = end+1;
			loc = format.indexOf("%(", start);
		}
		newFormat.append(format.substring(start));
		return String.format(newFormat.toString(), newArgs);		
	}

	public String getText(String formatString) 	throws IllegalFormatException {
		return getText(formatString, (Object[])null);
	}
	
	public String getText(String formatString, Object... args) 	throws IllegalFormatException {
		return String.format(translate(getLocale(), formatString), args);
	}
	
	public I18NString getLazy(String formatString, Object... args) 	{
		return new I18NStringImpl(this, formatString, args);
	}

	public I18NString getLazy(String format, Map<String, Object> args) throws IllegalFormatException {
		return new I18NStringImpl(this, format, null).withMap(args);
	}

	public I18NString getLazy(String format, Object argBean) {
		return new I18NStringImpl(this, format, null).with(argBean);

	}

	public I18NString getLazy(String format) throws IllegalFormatException {
		return new I18NStringImpl(this, format, null);
	}
	
}
